
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
#if(COMPACT_FRAMEWORK)
using System.Runtime.InteropServices;
#endif
namespace Swaf.BGuid
{
	/// <summary>
	/// Summary description for Uri.
	/// </summary>
	[Serializable]
	public class Guid : ICloneable, IConvertible, IComparable
	{
		protected System.Guid g = System.Guid.Empty;

		public Guid()
		{
#if(!COMPACT_FRAMEWORK)
			g = System.Guid.NewGuid();
#else
			g = PocketGuid.NewGuid();
#endif
		}


		public Guid(string strGuid)
		{
			if (strGuid != null)
			{
				if (strGuid.Length == 32)
					strGuid = strGuid.Substring(0, 8) + "-" + strGuid.Substring(8, 4) + "-" + strGuid.Substring(12, 4) +
								"-" + strGuid.Substring(16, 4) + "-" + strGuid.Substring(20);
				else if(string.Compare(strGuid,"null",true) != 0)
					g = new System.Guid(strGuid);
			}
		}

		public Guid(System.Guid g)
		{
			this.g = g;
		}
		public Guid(Guid g)
		{
			this.g = g.g;
		}
		public static Guid Parse(object initVal)
		{
			if (initVal is string)
				return ParseEx((string)initVal);
			else if (initVal is Guid)
				return ParseEx((Guid) initVal);
			else if (initVal is System.Guid)
				return ParseEx((System.Guid) initVal);
			else
				throw new BaseException("Invalid data type passed to Guid.Parse.  Valid parse types are string, BGuid.Guid and System.Guid");
		}
		private static Guid ParseEx(Guid initVal)
		{
			if (initVal != null)
				return new Guid(initVal);
			else
				return null;
		}
		public static Guid ParseEx(System.Guid initVal)
		{
			return new Guid(initVal);
		}
		public static Guid ParseEx(string initVal)
		{
			if (initVal.Equals(string.Empty))
				return new Guid();
			else
				return new Guid(initVal);
		}
		public static Guid TryParse(string value)
		{
			if(value != null && value.Length == 36)
				try
				{
					return new Guid(value);
				}
				catch (Exception) { }
			return null;
		}

		public static bool TryParse(string value, out Guid mg)
		{
			mg = null;
			if(value != null && (value.Length == 36 || value.Length == 32))
				try
				{
					mg = new Guid(value);
					return true;
				}
				catch (Exception) { }
			return false;
		}

		public static implicit operator System.Guid (Guid value)
		{
			return value.g;
		}

		public static bool operator ==(Guid a, Guid b) 
		{
			object oa = (object)a;
			object ob = (object)b;

			if (oa == null && ob == null)
				return true;
			else if (oa == null || ob == null)
				return false;
			else
				return (a.g == b.g);
		}

		public static bool operator !=(Guid a, Guid b) 
		{
			object oa = (object)a;
			object ob = (object)b;

			if (oa == null && ob == null)
				return false;
			else if (oa == null || ob == null)
				return true;
			else
				return (a.g != b.g);
		}

		public override string ToString()
		{
			return g.ToString().ToUpper();
		}

		public object Clone()
		{
			return new Guid(this.g);
		}

		public override int GetHashCode()
		{
			return this.g.GetHashCode();
		}

		public override bool Equals(object obj)
		{
			Guid l_objOther = (obj as Guid);

			if (l_objOther != null)
				return this.g.Equals(l_objOther.g);
			else
				return false;
		}

		public static Guid NewGuid() 
		{
			return new Guid();
		}

		static Guid s_empty = new Guid(System.Guid.Empty);
		public static Guid Empty 
		{
			get { return s_empty; }
		}

		#region IConvertible Members

		public ulong ToUInt64(IFormatProvider provider)
		{
			throw new NotSupportedException();
		}

		public sbyte ToSByte(IFormatProvider provider)
		{
			throw new NotSupportedException();
		}

		public double ToDouble(IFormatProvider provider)
		{
			throw new NotSupportedException();
		}

		public DateTime ToDateTime(IFormatProvider provider)
		{
			throw new NotSupportedException();
		}

		public float ToSingle(IFormatProvider provider)
		{
			throw new NotSupportedException();
		}

		public bool ToBoolean(IFormatProvider provider)
		{
			throw new NotSupportedException();
		}

		public int ToInt32(IFormatProvider provider)
		{
			throw new NotSupportedException();
		}

		public ushort ToUInt16(IFormatProvider provider)
		{
			throw new NotSupportedException();
		}

		public short ToInt16(IFormatProvider provider)
		{
			throw new NotSupportedException();
		}

		string System.IConvertible.ToString(IFormatProvider provider)
		{
			return this.g.ToString();
		}

		public byte ToByte(IFormatProvider provider)
		{
			throw new NotSupportedException();
		}

		public char ToChar(IFormatProvider provider)
		{
			throw new NotSupportedException();
		}

		public long ToInt64(IFormatProvider provider)
		{
			throw new NotSupportedException();
		}

		public System.TypeCode GetTypeCode()
		{
			return System.TypeCode.Object;
		}

		public decimal ToDecimal(IFormatProvider provider)
		{
			throw new NotSupportedException();
		}

		public object ToType(Type conversionType, IFormatProvider provider)
		{
			if (conversionType == typeof(System.Guid))
				return g;
			else if (conversionType == typeof(System.String))
				return g.ToString();
			else
				throw new NotSupportedException();
		}

		public uint ToUInt32(IFormatProvider provider)
		{
			throw new NotSupportedException();
		}

		#endregion

		#region IComparable Members

		public int CompareTo(object obj)
		{
			if (obj == null) return -1;

			if (obj.GetType() == typeof(System.Guid)) 
			{
				return this.g.CompareTo((System.Guid)obj);
			}
			else if (obj.GetType() == typeof(Guid)) 
			{
				return this.g.CompareTo(((Guid)obj).g);
			}
			else if (obj.GetType() == typeof(String)) 
			{
				return this.g.ToString().CompareTo(obj.ToString());
			}
			else
				return -1;
		}

		#endregion
	}

#if(COMPACT_FRAMEWORK)
	/// <summary>
	/// Generate GUIDs on the .NET Compact Framework.
	/// </summary>
	class PocketGuid
	{
		// guid variant types
		private enum GuidVariant
		{
			ReservedNCS = 0x00,
			Standard = 0x02,
			ReservedMicrosoft = 0x06,
			ReservedFuture = 0x07
		}

		// guid version types
		private enum GuidVersion
		{
			TimeBased = 0x01,
			Reserved = 0x02,
			NameBased = 0x03,
			Random = 0x04
		}
        
		// constants that are used in the class
		private class Const
		{
			// number of bytes in guid
			public const int ByteArraySize = 16;
        
			// multiplex variant info
			public const int VariantByte = 8;
			public const int VariantByteMask = 0x3f;
			public const int VariantByteShift = 6;

			// multiplex version info
			public const int VersionByte = 7;
			public const int VersionByteMask = 0x0f;
			public const int VersionByteShift = 4;
		}

		// imports for the crypto api functions
		private class WinApi
		{
			public const uint PROV_RSA_FULL = 1;
			public const uint CRYPT_VERIFYCONTEXT = 0xf0000000;

			[DllImport("coredll.dll")] 
			public static extern bool CryptAcquireContext(
				ref IntPtr phProv, string pszContainer, string pszProvider,
				uint dwProvType, uint dwFlags);

			[DllImport("coredll.dll")] 
			public static extern bool CryptReleaseContext( 
				IntPtr hProv, uint dwFlags);

			[DllImport("coredll.dll")] 
			public static extern bool CryptGenRandom(
				IntPtr hProv, int dwLen, byte[] pbBuffer);
		}
    
		// all static methods
		private PocketGuid()
		{
		}
    
		/// <summary>
		/// Return a new System.Guid object.
		/// </summary>
		public static System.Guid NewGuid()
		{
			IntPtr hCryptProv = IntPtr.Zero;
			System.Guid guid = System.Guid.Empty;
        
			try
			{
				// holds random bits for guid
				byte[] bits = new byte[Const.ByteArraySize];

				// get crypto provider handle
				if (!WinApi.CryptAcquireContext(ref hCryptProv, null, null, 
					WinApi.PROV_RSA_FULL, WinApi.CRYPT_VERIFYCONTEXT))
				{
					throw new SystemException(
						"Failed to acquire cryptography handle.");
				}
    
				// generate a 128 bit (16 byte) cryptographically random number
				if (!WinApi.CryptGenRandom(hCryptProv, bits.Length, bits))
				{
					throw new SystemException(
						"Failed to generate cryptography random bytes.");
				}
        
				// set the variant
				bits[Const.VariantByte] &= Const.VariantByteMask;
				bits[Const.VariantByte] |= 
					((int)GuidVariant.Standard << Const.VariantByteShift);

				// set the version
				bits[Const.VersionByte] &= Const.VersionByteMask;
				bits[Const.VersionByte] |= 
					((int)GuidVersion.Random << Const.VersionByteShift);
        
				// create the new System.Guid object
				guid = new System.Guid(bits);
			}
			finally
			{
				// release the crypto provider handle
				if (hCryptProv != IntPtr.Zero)
					WinApi.CryptReleaseContext(hCryptProv, 0);
			}
        
			return guid;
		}
	}
#endif

}
